home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1989 Massachusetts Institute of Technology
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of M.I.T. not be used in advertising or
- * publicity pertaining to distribution of the software without specific,
- * written prior permission. M.I.T. makes no representations about the
- * suitability of this software for any purpose. It is provided "as is"
- * without express or implied warranty.
- *
- * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
- * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
- * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Authors: Many and varied...
- */
-
- #ifndef lint
- static char sccs_id[] = "%W%";
- static char rcsid[] = "@(#)$Id: getloadavg.c,v 1.16 1991/06/21 12:51:15 paul Exp $";
- #endif /* !lint */
-
- #include "conf.h"
-
- /* Necessary as AIX has a typedef for syserr [err.c] in sysinfo.h */
- #ifndef _AIX
- # include "sendmail.h"
- #endif /* !_AIX */
-
- #ifdef DGUX
- # include <sys/dg_sys_info.h>
-
- int getloadavg( call_data )
- caddr_t call_data; /* pointer to (double) return value */
- {
- struct dg_sys_info_load_info load_info;
-
- dg_sys_info(&load_info,
- DG_SYS_INFO_LOAD_INFO_TYPE, DG_SYS_INFO_LOAD_VERSION_0);
-
- *(double *)call_data = load_info.one_minute;
- }
- #else /* DGUX */
-
- # ifdef UMAX
- /*
- *
- * FOR: Encore multimax UMAX 4.3.
- *
- * Extracted from get_stats() (written by John Robert LoVerso)
- * by Neil Rickert.
- *
- * Use inq_stats() to determine boottime, load average
- *
- */
-
- # include <sys/param.h> /* */
- # include <inq_stats/statistics.h>
- # include <inq_stats/procstats.h>
-
- /*
- * see dimension of ps_nrun[] in procstats.h
- */
- # ifndef PS_NRUNSIZE
- # define PS_NRUNSIZE 300
- # endif
-
- /*
- * Each entry in ps_nrun[] is count of runnable processes sampled every
- * 5 seconds. period[] contains the number of samples to use for the
- * intervals of {1,5,15} minutes. cexp[] contains constans for exponential
- * decay.
- */
- # define period 12
-
- int getloadavg( call_data )
- caddr_t call_data; /* pointer to (double) return value */
- {
- struct stat_descr Proc_info;
- struct proc_summary Proc_sum_data;
- register int i, index, interval;
-
- /*
- * struct to get process summary data,
- * esp circular buffer containing counts of runnable processes
- */
- Proc_info.sd_next = NULL;
- Proc_info.sd_subsys = SUBSYS_PROC;
- Proc_info.sd_type = PROCTYPE_SUMMARY;
- Proc_info.sd_addr = (char *) &Proc_sum_data;
- Proc_info.sd_size = sizeof (struct proc_summary);
- Proc_info.sd_sizeused = 0;
-
- /*
- * fill in Boot_data and Proc_sum_data structures
- */
- if (inq_stats(1, &Proc_info) != 0) {
- # ifdef LOG
- syslog(LOG_WARNING, "getloadavg: inq_stats(): %m");
- # endif /* LOG */
- return (-1);
- }
-
- /*
- * fastest (inverse shared sum) loop
- */
- index = Proc_sum_data.ps_nrunidx;
- interval = 0;
- *(double *)call_data = 0.0;
- for (; interval < period; interval++) {
- *(double *)call_data += Proc_sum_data.ps_nrun[index];
- if (--index < 0)
- index = PS_NRUNSIZE-1;
- }
-
- *(double *)call_data /= period;
- }
- # else /* UMAX */
-
- # ifdef _AIX
- /*
- * This version of this module (get_load.c) is specifically for the IBM
- * S/6000 AIX 3.1 platform. The copyright below applies to this module
- * only.
- *
- * Copyright (C) 1990 by the University of Illinois Board of Trustees.
- *
- * This code is distributed in the hope that it will be useful,
- * but without any warranty. No author or distributor accepts
- * responsibility to anyone for the consequences of using it or for
- * whether it serves any particular purpose or works at all, unless
- * s/he says so in writing.
- *
- * Author: Charley Kline, University of Illinois Computing Services
- * c-kline@uiuc.edu
- *
- */
-
- # include <sys/sysinfo.h>
- # include <unistd.h>
- # include <fcntl.h>
- # include <syslog.h>
- # include <math.h>
- # include <nlist.h>
-
- struct nlist kernelnames[] = {
- {"sysinfo", 0, 0, 0, 0, 0},
- {NULL, 0, 0, 0, 0, 0},
- };
-
-
- /* ARGSUSED */
- int
- getloadavg (call_data)
- caddr_t call_data; /* pointer to (double) return value */
- {
- double *loadavg = (double *)call_data;
- double loadav;
- static double avenrun = 0.;
- struct sysinfo si;
- static int rq_old = 0, ro_old = 0;
- static initted = 0;
- static int fd;
- double multiplier;
- double t;
-
- /*
- * * Do stuff we only need to do once per invocation, like opening *
- * the kmem file and fetching the parts of the symbol table.
- */
- if (!initted) {
- initted = 1;
- knlist (kernelnames, 1, sizeof (struct nlist));
- if ((fd = open ("/dev/kmem", O_RDONLY)) < 0)
- {
- # ifdef LOG
- syslog(LOG_WARNING, "getloadavg: open /dev/kmem: %m");
- # endif /* LOG */
- return (-1);
- }
- }
- /*
- * * Get the system info structure from the running kernel.
- */
- lseek (fd, kernelnames[0].n_value, SEEK_SET);
- if (read (fd, (char *)&si, sizeof (struct sysinfo)) != sizeof (struct sysinfo))
- {
- # ifdef LOG
- syslog(LOG_WARNING, "getloadavg: read /dev/kmem: %m");
- # endif /* LOG */
- return (-1);
- }
-
- /*
- * AIX doesn't keep the load average variables in the kernel; all
- * we can get is the current number of runnable processes by
- * observing the difference between the runque and runocc values in
- * sysinfo. Having done this, however, we can apply a TENEX-style
- * exponential time-average to it by computing an averaging multiplier
- * based on the sampling interval. This is then used to factor in *
- * the current number of running processes to our running load
- * average. The result "looks right" when observed in conjunction
- * with the process table and user activity.
- *
- * We subtract one from the number of running processes given us by
- * the kernel because for some reason AIX always calls one of the
- * kernel processes "runnable" even though it uses very little CPU.
- * Subtracting this out gives a load average near zero when the
- * machine is mostly idle, which is more familiar to those of us who
- * are used to bsd-style load averages.
- */
- t = (double) (si.runocc - ro_old);
- loadav = (double) (si.runque - rq_old) / t - 1.0;
- rq_old = si.runque;
- ro_old = si.runocc;
- multiplier = exp (-t / 60.);
- avenrun = multiplier * avenrun + (1.0 - multiplier) * loadav;
- /*
- * DEBUG printf("%d %d %f %f %f\n", si.runque, si.runocc, t, loadav,
- * avenrun);
- */
-
- *loadavg = avenrun;
- return (0);
- }
- # else /* !_AIX */
-
- /*
- * Get open(2) constants
- */
- # ifdef SYSV
- # ifndef macII
- # include <fcntl.h>
- # endif /* !macII */
- # endif /* SYSV */
- # include <sys/file.h>
- # ifdef USG
- # include <unistd.h>
- # endif /* USG */
-
- # ifdef att
- # define LOADSTUB
- # endif /* att */
-
- # ifdef apollo
- # include <apollo/base.h>
- # include <apollo/time.h>
- # ifdef notdef
- typedef struct {
- short state; /* ready, waiting, etc. */
- pinteger usr; /* user sr */
- linteger upc; /* user pc */
- linteger usp; /* user stack pointer */
- linteger usb; /* user sb ptr (A6) */
- time_$clock_t cpu_total; /* cumulative cpu used by process */
- unsigned short priority; /* process priority */
- } proc1_$info_t;
-
- /* Enable function prototypes for ANSI C and C++ */
- # if (defined(__STDC__) || defined(c_plusplus) || defined(__cplusplus)) \
- && !defined(__GNUC__)
- # define _PROTOTYPES
- # endif /* (__STDC__ || c_plusplus || __cplusplus) && !__GNUC__ */
-
- void proc1_$get_cput(
- # ifdef _PROTOTYPES
- time_$clock_t *cput
- # endif /* _PROTOTYPES */
- );
-
- void proc1_$get_info(
- # ifdef _PROTOTYPES
- short &pid,
- proc1_$info_t *info,
- status_$t *sts
- # endif /* _PROTOTYPES */
- );
- # ifdef _PROTOTYPES
- # undef _PROTOTYPES
- # endif /* _PROTOTYPES */
-
- # endif /* notdef */
- # endif /* apollo */
-
- # if !defined(macII) && !defined(apollo) && !defined(LOADSTUB)
- # include <nlist.h>
- # endif /* !macII && !apollo && !LOADSTUB */
-
- # ifdef sun
- # include <sys/param.h>
- # ifdef i386
- # include <kvm.h>
- # define KVM_ROUTINES
- # endif /* i386 */
- # endif /* sun */
-
- # if defined(mips) && !defined(sgi)
- # include <sys/fixpoint.h>
- # endif /* mips && !sgi */
-
- # ifdef CRAY
- # include <sys/param.h>
- # include <sys/sysinfo.h>
- # undef n_type
- # define n_type n_value
- # endif /* CRAY */
-
- # ifdef vax
- # include <sys/param.h>
- # endif /* vax */
-
- # ifdef sequent
- # include <sys/vm.h>
- # endif /* sequent */
-
- # ifdef macII
- # include <a.out.h>
- # include <sys/var.h>
- # define X_AVENRUN 0
- # define fxtod(i) (vec[i].high+(vec[i].low/65536.0))
- struct lavnum {
- unsigned short high;
- unsigned short low;
- };
- # endif /* macII */
-
- # ifdef unixpc
- # define FSCALE 64.0
- # endif /* unixpc */
-
- # if defined(UTEK) || defined(alliant)
- # define FSCALE 100.0
- # endif /* UTEK || alliant */
-
- # if (defined(sequent) || defined(NeXT) || defined(sgi)) && !defined(FSCALE)
- # define FSCALE 1000.0
- # endif /* (sequent || NeXT || sgi) && !FSCALE */
-
- # ifdef hp9000
- # include <sys/param.h>
- # endif /* hp9000 */
-
- # ifndef FSCALE
- # define FSHIFT 8 /* bits to right of fixed binary point */
- # define FSCALE (1<<FSHIFT)
- # endif /* !FSCALE */
-
- # ifdef __STDC__
- extern off_t lseek(int, off_t, int);
- extern void exit(int);
- # else /* !__STDC__ */
- extern long lseek();
- extern void exit();
- # endif /* __STDC__ */
-
- # if apollo
- /* ARGSUSED */
- int getloadavg( call_data )
- caddr_t call_data; /* pointer to (double) return value */
- {
- # ifdef notdef
- static int firstTime = 1;
- static int lastNullCpu;
- static int lastClock;
- time_$clock_t timeNow;
- double temp;
- proc1_$info_t info;
- status_$t st;
-
- proc1_$get_info( (short) 2, &info, &st );
- time_$clock( &timeNow );
-
- if (firstTime)
- {
- *(double *)call_data = 1.0;
- firstTime = 0;
- }
- else {
- temp = info.cpu_total.low32 - lastNullCpu;
- *(double *)call_data = 1.0 - temp / (timeNow.low32 - lastClock);
- }
-
- lastClock = timeNow.low32;
- lastNullCpu = info.cpu_total.low32;
- return(0);
- # else /* !notdef */
- double *avenrun = (double *) call_data;
- int i;
- status_$t st;
- long loadav[3];
- proc1_$get_loadav(loadav, &st);
- *avenrun = loadav[0] / (double) (1 << 16);
- return(0);
- # endif /* notdef */
- }
- # else /* !apollo */
- # ifdef KVM_ROUTINES
- /*
- * Sun 386i Code - abstracted to see the wood for the trees
- */
-
- /* ARGSUSED */
- void
- getloadavg( call_data )
- caddr_t call_data; /* pointer to (double) return value */
- {
- double *loadavg = (double *)call_data;
- long temp;
- static int init = 0;
- static struct nlist nl[2];
- static kvm_t *kd;
-
- if (!init) {
- kd = kvm_open("/vmunix", NULL, NULL, O_RDONLY, NULL);
- if (kd == (kvm_t *)0) {
- # ifdef LOG
- syslog(LOG_WARNING, "getloadavg: kvm_open /vmunix: %m");
- # endif /* LOG */
- return (-1);
- }
-
- nl[0].n_name = "avenrun";
- nl[1].n_name = NULL;
-
- if (kvm_nlist(kd, nl) != 0) {
- # ifdef LOG
- syslog(LOG_WARNING, "getloadavg: kvm_nlist /vmunix: %m");
- # endif /* LOG */
- return (-1);
- }
- init = 1;
- }
-
- if (nl[0].n_value == 0) {
- return (-1);
- }
- if (kvm_read(kd, nl[0].n_value, (char *)&temp, sizeof (temp)) !=
- sizeof (temp)) {
- # ifdef LOG
- syslog(LOG_WARNING, "getloadavg: kvm_read /vmunix: %m");
- # endif /* LOG */
- return (-1);
- }
- *loadavg = (double)temp/FSCALE;
- return(0);
- }
- # else /* !KVM_ROUTINES */
- # ifdef LOADSTUB
-
- /* ARGSUSED */
- int getloadavg( call_data )
- caddr_t call_data; /* pointer to (double) return value */
- {
- *(double *)call_data = 1.0;
- }
-
- # else /* !LOADSTUB */
-
- # ifndef KMEM_FILE
- # define KMEM_FILE "/dev/kmem"
- # endif /* !KMEM_FILE */
-
- # ifndef KERNEL_FILE
-
- # ifdef NeXT
- # define KERNEL_FILE "/mach"
- # endif /* NeXT */
-
- # ifdef alliant
- # define KERNEL_FILE "/unix"
- # endif /* alliant */
-
- # ifdef CRAY
- # define KERNEL_FILE "/unicos"
- # endif /* CRAY */
-
- # ifdef hpux
- # define KERNEL_FILE "/hp-ux"
- # endif /* hpux */
-
- # ifdef macII
- # define KERNEL_FILE "/unix"
- # endif /* macII */
-
- # ifdef mips
- # ifdef SYSTYPE_SYSV
- # define KERNEL_FILE "/unix"
- # else /* !SYSTYPE_SYSV */
- # define KERNEL_FILE "/vmunix"
- # endif /* SYSTYPE_SYSV */
- # endif /* mips */
-
- # ifdef sequent
- # define KERNEL_FILE "/dynix"
- # endif /* sequent */
-
- /*
- * provide default for everyone else
- */
- # ifndef KERNEL_FILE
- # ifdef SYSV
- # define KERNEL_FILE "/unix"
- # else /* !SYSV */
- # define KERNEL_FILE "/vmunix"
- # endif /* SYSV */
- # endif /* KERNEL_FILE */
- # endif /* KERNEL_FILE */
-
- # ifndef KERNEL_LOAD_VARIABLE
- /*
- * provide default
- */
- # ifdef USG
- # define KERNEL_LOAD_VARIABLE "sysinfo"
- # define SYSINFO
- # else /* !USG */
- # define KERNEL_LOAD_VARIABLE "_avenrun"
- # endif /* USG */
-
- # ifdef alliant
- # undef KERNEL_LOAD_VARIABLE
- # define KERNEL_LOAD_VARIABLE "_Loadave"
- # endif /* alliant */
-
- # ifdef CRAY
- # if defined(CRAY2) && OSMAJORVERSION == 4
- # undef KERNEL_LOAD_VARIABLE
- # define KERNEL_LOAD_VARIABLE "avenrun"
- # else /* !CRAY2 || OSMAJORVERSION != 4 */
- # undef KERNEL_LOAD_VARIABLE
- # define KERNEL_LOAD_VARIABLE "sysinfo"
- # define SYSINFO
- # endif /* CRAY2 && OSMAJORVERSION == 4 */
- # endif /* CRAY */
-
- # ifdef hpux
- # ifdef hp9000s800
- # undef KERNEL_LOAD_VARIABLE
- # define KERNEL_LOAD_VARIABLE "avenrun"
- # endif /* hp9000s800 */
- # endif /* hpux */
-
- # ifdef mips
- # ifdef SYSTYPE_SYSV
- # undef KERNEL_LOAD_VARIABLE
- # define KERNEL_LOAD_VARIABLE "avenrun"
- # else /* !SYSTYPE_SYSV */
- # undef KERNEL_LOAD_VARIABLE
- # define KERNEL_LOAD_VARIABLE "_avenrun"
- # endif /* SYSTYPE_SYSV */
- # endif /* mips */
-
- # ifdef unixpc
- # undef KERNEL_LOAD_VARIABLE
- # define KERNEL_LOAD_VARIABLE "avenrun"
- # endif /* unixpc */
- # endif /* KERNEL_LOAD_VARIABLE */
-
- # ifdef macII
- struct var v;
- static int pad[2]; /* This padding is needed if getloadavg compiled on */
- /* a/ux 1.1 is executed on a/ux 1.0, because */
- /* the var structure had too much padding in 1.0, */
- /* so the 1.0 kernel writes past the end of the 1.1 */
- /* var structure in the uvar() call. */
- static struct nlist nl[2];
- static struct lavnum vec[3];
- # else /* not macII */
- static struct nlist namelist[] = { /* namelist for vmunix grubbing */
- # define LOADAV 0
- # ifdef NeXT
- {{KERNEL_LOAD_VARIABLE}},
- {{0},0}
- # else /* !NeXT */
- # ifdef unixpc
- { KERNEL_LOAD_VARIABLE, },
- { (char *)0, },
- # else /* !unixpc */
- {KERNEL_LOAD_VARIABLE},
- {0}
- # endif /* unixpc */
- # endif /* NeXT */
- };
- # endif /* macII */
-
-
- /* ARGSUSED */
- int getloadavg( call_data )
- caddr_t call_data; /* pointer to (double) return value */
- {
- double *loadavg = (double *)call_data;
- static int init = 0;
- static kmem;
- static long loadavg_seek;
- # ifdef macII
- # ifdef __STDC__
- extern int nlist(const char *, struct nlist *);
- # else /* !__STDC__ */
- extern int nlist();
- # endif /* __STDC__ */
-
- if(!init) {
- int i;
-
- (void) strcpy(nl[0].n_name, "avenrun");
- nl[1].n_name[0] = '\0';
-
- kmem = open(KMEM_FILE, O_RDONLY);
- if (kmem < 0) {
- # ifdef LOG
- syslog(LOG_WARNING, "getloadavg: open %s: %m", KMEM_FILE);
- # endif /* LOG */
- return (-1);
- }
-
- uvar(&v);
-
- if (nlist( KERNEL_FILE, nl) != 0) {
- # ifdef LOG
- syslog(LOG_WARNING, "getloadavg: nlist %s: %m", KERNEL_FILE);
- # endif /* LOG */
- return (-1);
- }
- for (i = 0; i < 2; i++) {
- nl[i].n_value = (int)nl[i].n_value - v.v_kvoffset;
- }
- init = 1;
- }
- # else /* !macII */
- # ifdef unixpc
- # ifdef __STDC__
- extern int nlist(const char *, struct nlist *);
- # else /* !__STDC__ */
- extern int nlist();
- # endif /* __STDC__ */
-
- if (!init)
- {
- if (nlist(KERNEL_FILE, namelist) != 0)
- return (-1);
- loadavg_seek = (long)namelist[0].n_value;
- if ((kmem = open(KMEM_FILE, O_RDONLY)) < 0)
- return (-1);
- init = 1;
- }
- # else /* !unixpc */
- # if !defined(sgi) && !defined(BSD4_4)
- extern void nlist();
- # else /* sgi || BSD4_4 */
- extern nlist();
- # endif /* !sgi && !BSD4_4 */
-
- if(!init) {
- nlist( KERNEL_FILE, namelist);
- /*
- * Some systems appear to set only one of these to Zero if the entry could
- * not be found, I hope no_one returns Zero as a good value, or bad things
- * will happen to you. (I have a hard time believing the value will
- * ever really be zero anyway). CDP 5/17/89.
- */
- if (namelist[LOADAV].n_type == 0 ||
- namelist[LOADAV].n_value == 0) {
- return (-1);
- }
- loadavg_seek = namelist[LOADAV].n_value;
- # if defined(mips) && defined(SYSTYPE_SYSV)
- loadavg_seek &= 0x7fffffff;
- # endif /* mips && SYSTYPE_SYSV */
- # if defined(CRAY) && defined(SYSINFO)
- loadavg_seek += ((char *) (((struct sysinfo *)NULL)->avenrun)) -
- ((char *) NULL);
- # endif /* CRAY && SYSINFO */
-
- kmem = open(KMEM_FILE, O_RDONLY);
- if (kmem < 0) {
- # ifdef LOG
- syslog(LOG_WARNING, "getloadavg: open %s: %m", KMEM_FILE);
- # endif /* LOG */
- return (-1);
- }
- init = 1;
- }
- # endif /* unixpc */
- (void) lseek(kmem, loadavg_seek, 0);
- # endif /* macII */
- # if defined(sun) || defined (UTEK) || defined(sequent) || \
- defined(alliant) || defined(hp9000) || defined(sgi) || defined(NeXT) || \
- defined(unixpc)
- {
- long temp;
- (void) read(kmem, (char *)&temp, sizeof(long));
- *loadavg = (double)temp/FSCALE;
- }
- # else /* !sun && !UTEK && !sequent && !alliant && !hp9000 && !sgi && !NeXT && !unixpc */
- # ifdef macII
- {
- lseek(kmem, (long)nl[X_AVENRUN].n_value, 0);
- read(kmem, vec, 3*sizeof(struct lavnum));
- *loadavg = fxtod(0);
- }
- # else /* !macII */
- # if defined(mips)
- {
- fix temp;
- (void) read(kmem, (char *)&temp, sizeof(fix));
- *loadavg = FIX_TO_DBL(temp);
- }
- # else /* !mips */
- (void) read(kmem, (char *)loadavg, sizeof(double));
- # endif /* mips */
- # endif /* macII */
- # endif /* sun || UTEK || sequent || alliant || hp9000 || sgi || NeXT || unixpc */
- return(0);
- }
- # endif /* LOADSTUB */
- # endif /* KVM_ROUTINES */
- # endif /* apollo */
- # endif /* _AIX */
- # endif /* UMAX */
- #endif /* DGUX */
-